"""
Chio/screen: Вспомогательные функции и классы представления.
Author: Milinuri Nirvalen
Ver: v3
"""

import re
from datetime import datetime
from shutil import get_terminal_size


# Справка об использовании select()
select_help = """
Справка о способах выбора элементов:

1. ENTER - первый элемент из предложенных.
2. По номеру элемента."""


def rc(text):
    """Возвращает очишенный от цветовых кодов текст."""
    return re.sub(r'\033\[[0-9]*m', '', text)

def clear_console():
    print('\n'*get_terminal_size()[1])

def row(sim='-'):
    print(sim*get_terminal_size()[0])

def iprint(text, **params):
    """Обёртка над print() для простой записи вывода в 1 строку.
    :param text: Cтроки для отображения в print()
    :param params: Дополнительные параметры, переловаемые в print()"""

    lt = len(rc(text))
    size = get_terminal_size()[0]

    if lt > size:
        part_lt = size//2
        text = text[:part_lt] + "... " + text[-(size-part_lt-5):]
        
    print(f"{text}{' '*(size-lt)}\033[0m", end="\r", **params)

def select(selectors):
    """Меню выбора элемента.
    :param selectors: словарь элементов {ключ: значение}
    
    :return: выбранный ключ элемента"""
    
    if isinstance(selectors, list):
        temp = dict()

        for x in selectors:
            temp[x] = x
        selectors = temp

    prompt = "\033[90mtype \033[32mhelp \033[90mor select>\033[95m "

    # отображение вариантов выбора
    for i, x in enumerate(selectors.values()):
        print(f'\033[33m{i+1} \033[0m{x}')

    while True:
        i = input(prompt).lower()
        print("\033[0m", end="\r")

        if i == "help":
            print(select_help)

        elif not i:
            return list(selectors)[0]

        elif i.isdigit() and int(i) <= len(selectors):
            return list(selectors)[int(i)-1]


# продвинутые элементы представления
# ==================================

class Logger:
    """Отображение сообщений в терминале.
    :param log_level: Уровень логгирования
    :param print_date: Отображать ли даты сообщений
    :param date_format: Формат отображения даты"""
    
    def __init__(self, log_group=None, log_level=1, print_date=False, 
                 date_format="%H:%M:%S"):
        super(Logger, self).__init__()
        self.log_group = log_group
        self.log_level = log_level
        self.print_date = print_date
        self.date_format = date_format
        
        # Уровни логгирования (по значимости)
        # -----------------------------------
        # 0 - debug   : Отладочная информация
        # 1 - info    : Сообщения о процессе выполения действий
        # 2 - cmplited: Сообщения о завершённых действиях
        # 3 - warning : Предупреждения во время выполнения действия
        # 4 - error   : Ошибки, мешающие выполнению действия

        self.groups = [
            {'name':'debug', 'prefix':f'\033[95m[D]\033[0m'},
            {'name':'info', 'prefix':f'\033[96m[I]\033[0m'},
            {'name':'complited', 'prefix':f'\033[92m[C]\033[0m'},
            {'name':'warning', 'prefix':f'\033[93m[W]\033[0m'},
            {'name':'error', 'prefix':f'\033[91m[E]\033[0m'}
        ]
    
    def date(self):
        t = datetime.now().strftime(self.date_format)
        return f"\033[90m{t}\033[0m"
    
    def group(self, text):
        print(f'\033[95m::\033[0m\033[1m {text}\033[0m')

    def log(self, text, log_level=1, group=None, deep=0, date=False):
        """Выводит сообщение в терминал.

        :param text: Текст сообщения
        :param log_level: Важность сообщения
        :param group: Группа сообщения
        :param deep: Отступ сообщения
        :param date: Отобрвжвть ли дату сообщения"""

        s = get_terminal_size()[0]
        prefix = self.groups[min([log_level, len(self.groups)-1])]['prefix']
        
        group_msg = ""

        if self.log_group:
            group_msg += f' \033[90m{self.log_group} '

        if group:
            group_msg += f'\033[90m[\033[34m{group}\033[90m] '
        
        if self.print_date or date:
            log_text = f'{self.date()}{group_msg}{" "*(deep*2)}{prefix} {text}'
        else:
            log_text = f'{group_msg}{" "*(deep*2)}{prefix} {text}'

        if log_level >= self.log_level:
            print(f'{log_text}{" "*(s-len(rc(log_text)))}\033[0m')

    def logtest(self):
        # выводит все типы логов
        for x in range(len(self.groups)):
            n = self.groups[x]['name']
            print(f'log level: {x}')
            self.log(f'{n} log message', log_level=x)
            self.log(f'{n} deep message', log_level=x, deep=2)
            self.log(f'{n} group log message', log_level=x, group='aaa')
            self.log(f'{n} date message', log_level=x, date=True)
            

    # Сокращения для лог-функций
    # ==========================

    def debug(self, text, group=None, deep=1):
        self.log(text, 0, group, deep)

    def info(self, text, group=None, deep=0):
        self.log(text, 1, group, deep)

    def complite(self, text, group=None, deep=0):
        self.log(text, 2, group, deep)

    def warn(self, text, group=None, deep=0):
        self.log(text, 3, group, deep)

    def error(self, text, group=None, deep=0):
        self.log(text, 4, group, deep)


class ProgressBar:
    """Простой класс для отрисовки прогресс-баров
    :param total: Максимальное значение прогресс-бара
    :param prefix: Структура прогресс-бара

    Prefix:
        %p - Линия прогресса
        %i - Текущенн значение линии прогресса
        %t - Максимальное значение линии прогресса
        %r - Сколько процентов линии прогресса пройдено
        %c - Сколько осталось пройти линии пргресса значений"""

    def __init__(self, total, prefx='%r [%p] %c'):
        super(ProgressBar, self).__init__()
        self.total = total
        self.i = 0
        self.prefx = prefx

    def progress_line(self):
        """Отрисовывает прогресса-линию.
        :return: Текстовая линия-прогресса"""
        
        size = round(get_terminal_size()[0]/100*25) 
        self.i = self.total if self.i > self.total else self.i
        pr = round(self.i/self.total*size)
        fpr = round(self.i/self.total*100, 1)
        patterns = {
            '%p': f'\033[92m{"#"*(pr)}\033[0m{"-"*(size-pr)}',
            '%i': self.i,
            '%t': self.total,
            '%r': f'{" "*(5-len(str(fpr)))}{fpr}%',
            '%c': self.total-self.i
        } 

        res = self.prefx
        for k, v in patterns.items():
            res = res.replace(k, str(v))
        return res


    def iter(self, text=None):
        """Отрисовывает прогресс-линию в терминал."""
        self.i += 1
        if text is None:
            return True
            
        iprint(f'{self.progress_line()} {text}')



# В процессе переноса
# ===================

'''
def print_list(l, name=None):
    """Выводит список в виде древа.

    :param l: Список для прдставления.
    :param name: Имя дерева."""
    
    print(f"[{len(target)}] " + name or 'tree')

    for u in l:
        if u == l[len(lt)-1]:
            print(self.colored(f'  └───[{u}'))
        else:
            print(self.colored(f'  ├───[{u}'))

def form(text):
    """Отрисовывает рамку с текстом.

    :param text: Текст в рамке"""
    
    if isinstance(text, list):
        pass
    elif isinstance(text, str):
        text = text.splitlines()
    else:
        text = str(text)

    s = self.size[0]-10
    st = s-4

    print('\n'+' '*5+'┏'+'━'*(s-3)+'┑'+' '*5)

    for line in text:
        if len(self.rc(line)) < st:
            self.cprint(f'     ┃ {line}{" "*(st-len(self.rc(line)))}│     ')

        else:
            i = round(len(self.rc(line))/st)
            for x in range(round(len(self.rc(line))/st)):
                if x != i:
                    string = line[x*st:(x+1)*st]
                else:
                    string = line[x*st:]

                self.cprint(f'     ┃ {string}{" "*(st-len(string))}│     ')

    print(' '*5+'┖'+'─'*(s-3)+'┘'+' '*5)

def window(self, *lines, **params):
    # border
    border_type = params.get('border', 'standart')
    scheme = params.get('scheme', ['h', 'm', 'f'])
    indent = 0
    borders = {'standart': ['╔', '╗', '╚', '╝', '═', '║'],
                'retro': ['+', '+', '+', '+', '-', '|']}
    border = borders[border_type]

    # lenght window
    if 'lenght' in params:
        line = params['lenght']
    else:
        line = max([len(x) for x in lines])
        if line % 2:
            line += 1

    if params.get('pos') == 'right':
        indent = self.size[0] - 2 - line

    # render
    for x in scheme:
        if x == 'h':
            print(' '*indent+border[0]+border[4]*line+border[1])
        elif x == 'f':
            print(' '*indent+border[2]+border[4]*line+border[3])
        elif x == 'm':
            for l in lines:
                print(' '*indent+border[5]+l+' '*(line-len(l))+border[5])
'''

